<?php
declare (strict_types = 1);

namespace app\live\model;

use app\api\model\WxApi;
use app\common\model\Config;
use think\Model;

/**
 * @mixin \think\Model
 */
class LiveBroadcast extends Model
{
    public $status = [
        101=>'直播中',
        102=>'未开始',
        103=>'已结束',
        104=>'禁播',
        105=>'暂停',
        106=>'异常',
        107=>'已过期',
    ];
    public $count = '';//数据总数
    public $error = '';//报错
    public $imgkey = 'livebroadcastimg_';
    public $goodskey = 'livebroadcastgoods_';
    public $createkey = 'createlive_';
    public $errkey = 'liveerr_';
    public $path = 'live_goods_img/';


    /*
     * 获取直播列表
     */
    public function getList()
    {
        try{
            $data = Input('post.');
            //查询条件
            if(!empty($data['title'])){
                $where[] = ['u.nickname|l.title','like','%'.trim($data['title']).'%'];
            }
            if(!empty($data['type'])) $where[] = ['l.type_id','=',$data['type']];
//            $where[] = ['l.end_time', '>', time()];
            $where[] = ['l.status', '=', 2];
            $where[] = ['l.is_display', '=', 1];
            $where[] = ['l.is_delete', '=', 0];
            $limit = isset($data['limit'])&&!empty($data['limit']) ? $data['limit'] : 15;//每页显示数据
            $query = ['page' => (isset($data['page']) ? $data['page'] : 1)];//分页参数
            $field = 'l.id,l.uid,l.room_id,l.title,u.nickname,u.avatarurl,l.share,l.type,l.type_id,l.playback_url,l.start_time,l.end_time';
            $item = $this->alias('l')->join('user u','l.uid=u.id','left')->where($where)->field($field)->order('l.start_time asc')->paginate($limit, false, array('query'=>$query));
            $list = empty($item) ? array(): $item->toArray();
            if(!empty($list['data'])){
                foreach($list['data'] as $k=>$v){
                    $list['data'][$k]['title'] = emojiDecode($v['title']);
                    $list['data'][$k]['nickname'] = emojiDecode($v['nickname']);
                    $list['data'][$k]['share'] = getApiDominUrl($v['share']);
                    $list['data'][$k]['playback_url'] = $v['playback_url']?:'';
                }
            }
            return $list;
        }catch (\Exception $e){
            if(stristr($e->getMessage(),'SQLSTATE')){
                $this->error = '数据走丢了，请稍后再试！';
            }else $this->error = $e->getMessage();
            return false;
        }
    }


    /*
     * 获取预告直播列表
     */
    public function getNoticeList()
    {
        try{
            $data = Input('post.');
            //查询条件
            $where[] = ['l.end_time', '>', time()-600];
            $where[] = ['l.status', '=', 1];
            $where[] = ['l.is_display', '=', 1];
            $where[] = ['l.is_delete', '=', 0];
            $limit = isset($data['limit'])&&!empty($data['limit']) ? $data['limit'] : 15;//每页显示数据
            $query = ['page' => (isset($data['page']) ? $data['page'] : 1)];//分页参数
            $field = 'l.id,l.uid,l.room_id,l.title,u.nickname,u.avatarurl,l.share';
            $item = $this->alias('l')->join('user u','l.uid=u.id','left')->where($where)->field($field)->order('l.start_time asc')->paginate($limit, false, array('query'=>$query));
            $list = empty($item) ? array(): $item->toArray();
            if(!empty($list['data'])){
                foreach($list['data'] as $k=>$v){
                    $list['data'][$k]['title'] = emojiDecode($v['title']);
                    $list['data'][$k]['nickname'] = emojiDecode($v['nickname']);
                    $list['data'][$k]['share'] = getApiDominUrl($v['share']);
                }
            }
            return $list;
        }catch (\Exception $e){
            if(stristr($e->getMessage(),'SQLSTATE')){
                $this->error = '数据走丢了，请稍后再试！';
            }else $this->error = $e->getMessage();
            return false;
        }
    }


    /*
     * 获取我的直播列表
     */
    public function getMyList($id)
    {
        try{
            $data = Input('post.');
            //查询条件
            if(!empty($data['title'])){
                $where[] = ['l.title','like','%'.trim($data['title']).'%'];
            }
            if(!empty($data['type'])) $where[] = ['l.type_id','=',$data['type']];
            $where[] = ['l.uid', '=', $id];
            $where[] = ['l.is_delete', '=', 0];
            $limit = isset($data['limit'])&&!empty($data['limit']) ? $data['limit'] : 15;//每页显示数据
            $query = ['page' => (isset($data['page']) ? $data['page'] : 1)];//分页参数
            $field = 'l.id,l.uid,l.room_id,l.title,u.nickname,u.avatarurl,l.share,l.type,l.type_id,l.playback_url,l.status,l.is_display,l.start_time,l.end_time';
            $item = $this->alias('l')->join('user u','l.uid=u.id','left')->where($where)->field($field)->order('l.start_time desc')->paginate($limit, false, array('query'=>$query));
            $list = empty($item) ? array(): $item->toArray();
            if(!empty($list['data'])){
                #$statusMap = [0=>'待审核',1=>'预热中',2=>'直播中',3=>'回放',4=>'已结束',5=>'已过期'];
                #$is_displayMap = [-1=>'发布失败',0=>'待发布',1=>'已发布',2=>'已下架'];
                foreach($list['data'] as $k=>$v){
                    $list['data'][$k]['title'] = emojiDecode($v['title']);
                    $list['data'][$k]['nickname'] = emojiDecode($v['nickname']);
                    $list['data'][$k]['share'] = getApiDominUrl($v['share']);
                    $list['data'][$k]['playback_url'] = $v['playback_url']?:'';
                    #$list['data'][$k]['status'] = $statusMap[$v['status']];
                    #$list['data'][$k]['is_display'] = $is_displayMap[$v['is_display']];
                }
            }
            return $list;
        }catch (\Exception $e){
            if(stristr($e->getMessage(),'SQLSTATE')){
                $this->error = '数据走丢了，请稍后再试！';
            }else $this->error = $e->getMessage();
            return false;
        }
    }


    /*
     * 删除我的直播
     */
    public function delLive($id)
    {
        try{
            if(empty($id)) exception('请先登录!');
            $data = Input('post.');
            if(empty($data['id'])||!is_numeric($data['id'])) exception('请选择要删除的直播间!');
            $info = $this->field('id,start_time,end_time,add_time')->where(['id'=>$data['id'],'uid'=>$id,'is_delete'=>0])->find();
            if(empty($info)) exception('找不到该直播间!');
            $is_ok = $this->where(['id'=>$info['id']])->update(['status'=>0,'is_display'=>2,'is_delete'=>1]);
            if($is_ok){
                $redis = getRedis();
                $redis->hSet($this->createkey.date('Ymd', $info['add_time']).'_'.$id, $info['start'].'-'.$info['end'], 0);//删除直播间，清楚房间id
                $redis->hDel($this->goodskey.$id, $info['start'].'-'.$info['end']);//删除直播间清楚对应的商品记录  商品数量
                $list = (new LiveBroadcastRelation())->field('goods_id')->where(['live_broadcast_id'=>$info['id']])->select()->toArray();
                if(!empty($list)){
                    //删除直播间清楚对应的商品记录  商品id和对应的时间段
                    foreach($list as $v){
                        $delInfo = $redis->hDel($this->goodskey.date('Ymd', $info['add_time']).'_'.$v['goods_id'], $info['start'].'-'.$info['end']);
                    }
                }
            }
            return $is_ok;
        }catch (\Exception $e){
            if(stristr($e->getMessage(),'SQLSTATE')){
                $this->error = '数据走丢了，请稍后再试！';
            }else $this->error = $e->getMessage();
            return false;
        }
    }

    /*
     * 创建直播间
     */
    public function createliveBroadcast($user)
    {
        try{
            if(empty($user)) exception('请先登录!');
            $redis_key = $this->createkey.date('Ymd').'_'.$user->id;
            $redis = getRedis();
            $liveInfo = $redis->hKeys($redis_key);//获取所有创建成功的时间key
            $max = (new Config())->toData('live');
            if(count($liveInfo) >= $max['live_limit']??5) exception("每天只能申请{$max['live_limit']}场直播!");//限制每天创建直播数
            $err = $redis->get($this->errkey.$user->id);
            if(!empty($err)&&$err>=3) exception('手速太快了，请骚后再试!');//限制2秒err内只能请求3次
            $data = Input('post.');
            if(empty($data['title'])) exception('请填写直播间名称!');
            if(empty($data['wechat'])) exception('请填写主播微信号!');
            if(empty($data['coverImg'])) exception('请先选择直播背景图!');
            if(empty($data['shareImg'])) exception('请先选择直播分享图!');
            if(!isset($data['screen'])) exception('请先选择横屏/竖屏直播!');
            if(empty($data['type_id'])) exception('请先选择直播分类!');
            if(empty($data['type'])) exception('请选择直播类型!');
            if($data['type'] == 1&&empty($data['goods'])) exception('请选择加入直播间的商品!');
            if(!empty($data['goods'])&&$data['type'] == 1){
                if(empty($data['goods_key'])) exception('选择的商品格式有误!');
                $data['goods'] = explode(',',$data['goods']);
                if(empty($data['goods'])||!is_array($data['goods'])) exception('选择的商品格式有误!');
                if(count($data['goods'])>$max['goods_limit']) exception("每场直播只能申请{$max['goods_limit']}件商品!");
            }
            if(empty($data['start'])||empty($data['end'])) exception('请先选择直播开始/结束时间!');
            if($data['coverImg'] != $data['shareImg']) exception('请图片获取异常，请重新上传!1');
            $img = $this->getUploadImgMidByKey($user->id,$data['coverImg']);
            if(empty($img['fm'])) exception('分享图不能为空!');
            if(empty($img['bj'])) exception('背景图不能为空!');
            $imgInfo['fm'] = explode('***',$img['fm']);
            $imgInfo['bj'] = explode('***',$img['bj']);
            if(!isset($imgInfo['bj'][1])||!isset($imgInfo['fm'][1])) exception('请图片获取异常，请重新上传!3');
            else{
                $data['coverImg'] = $imgInfo['bj'][1];
                $data['shareImg'] = $imgInfo['fm'][1];
            }
            $data['start'] = strtotime(date('Y-m-d'. $data['start']));
            $data['end'] = strtotime(date('Y-m-d'. $data['end']));
            if($data['start'] < (time()+900)) exception('请提前15分钟申请直播，开始时间必须在15分钟以后的!');
            if(!empty($liveInfo)){
                // 遍历已创建的直播时间key判断是否重复或时间重叠
                foreach($liveInfo as $v){
                    if($v == $data['start'].'-'.$data['end']) exception('已创建成功，请勿重新创建!');
                    $time = explode('-',$v);
                    $is_value = $redis->hGet($redis_key, $v);
                    if(!empty($is_value)){
                        if($data['start'] >= $time[0]&&$data['start'] < $time[1]) exception('该时间段已创建直播，请更改时间段!');
                        if($data['end'] > $time[0]&&$data['end'] <= $time[1]) exception('该时间段已创建直播，请更改时间段!');
                        if($data['start'] <= $time[0]&&$data['end'] >= $time[1]) exception('该时间段已创建直播，请更改时间段!');
                    }
                }
            }
            $data['name'] = isset($user->nickName) ? $user->nickName : $user->nickname;
            if(mb_strlen($data['name']) > 15) $data['name'] = mb_substr($data['name'], 0, 14, 'utf-8').'...';
            elseif(mb_strlen($data['name']) < 3) $data['name'] .= '的直播';
            $data['uid'] = $user->id?:0;
            //检查直播分类id是否存在
            $checkType = (new LiveBroadcastType())->checkType($data['type_id']);
            if(!$checkType) exception('不存在此分类!');
            //检查商品是否已选择
            $goodsModel = new LiveBroadcastGoods();
            if(!empty($data['goods'])&&$data['type'] == 1) {
                //判断提交的商品是否有更改，是否能更改成功
                $is_check = $goodsModel->checkGoodsAndSelect($data['goods'], $data['goods_key'], ['start' => $data['start'], 'end' => $data['end']], $user->id);
                if (is_array($is_check)) {
                    foreach ($is_check as $v) if ($v != true) exception('商品加入直播间失败，请重试!');
                } elseif ($is_check != true) exception('商品加入直播间失败，请重试!');
            }
            $req = [
                'uid'=>$user->id,
                'title'=>$data['title'],
                'wechat'=>$data['wechat'],
                'img'=>$imgInfo['bj'][0],
                'share'=>$imgInfo['fm'][0],
                'type'=>$data['type'],
                'type_id'=>$data['type_id'],
                'start_time'=>$data['start'],
                'end_time'=>$data['end'],
                'add_time'=>time(),
                'is_display'=>1,
                'status'=>1,
            ];
            //调用微信创建直播间接口
            $model = new WxApi();
            $wxReq = $model->createLiveBroadcast($data);
            if($wxReq==false && !empty($model->error)){
                //设置接口err2秒内只能请求3次
                $is_exists = $redis->exists($this->errkey.$user->id);
                if(!$is_exists) $redis->setex($this->errkey.$user->id, 2, 1);
                else $redis->incr($this->errkey.$user->id);
                exception($model->error);
            }
            if(isset($wxReq['roomId'])) $req['room_id'] = $wxReq['roomId'];
            //直播表添加记录
            $liveId = $this->insertGetId($req);
            //创建成功，写入redis
            // 直播详情表 添加记录
            LiveBroadcastInfo::insertGetId([
                'live_id'=>$liveId,
                'uid'  => $user->id,
                'day_month' => date('Ym'),
                'time_day' => date('Ymd')
            ]);
            //添加商品记录
            if(!empty($wxReq['roomId'])&&!empty($liveId)){
                $redis->hSet($redis_key, $data['start'].'-'.$data['end'], $liveId);//设置创建成功的时间key
                $redis->set($this->errkey.$user->id, 0);//清空请err求数
                if(!empty($data['goods'])){
                    $relationModel = new LiveBroadcastRelation();
                    $goodsReq = $relationModel->add(['uid'=>$user->id,'live_id'=>$liveId,'room_id'=>$wxReq['roomId']], $data['goods'], ['start'=>$data['start'],'end'=>$data['end']]);
                    if($goodsReq == false){
                        if(!empty($req['desc'])) $req['desc'] = $req['desc'].'@@@'.$relationModel->error;
                        else $req['desc'] = $relationModel->error;
                        $this->where('id',$liveId)->update(['desc'=>$req['desc'],'status'=>0]);
                        //商品添加失败删除redis缓存
                        $redis->hDel($goodsModel->rekey.$user->id, $data['start'].'-'.$data['end']);
                        foreach($data['goods'] as $v){
                            $redis->hDel($goodsModel->rekey.date('Ymd').'_'.$v, $data['start'].'-'.$data['end']);
                        }
                        exception('直播间已创建，商品添加失败:'.$relationModel->error);
                    }
                }
            }
            return ['room_id'=>$wxReq['roomId']??0];
        }catch (\Exception $e){
            if(stristr($e->getMessage(),'SQLSTATE')){
                $this->error = '数据走丢了，请稍后再试！';
            }else $this->error = $e->getMessage();
            return false;
        }
    }

    /*
     * 上传直播间图片素材
     */
    public function uploadImg($id)
    {
        try{
            $data = Input('post.');
            if(empty($data['type'])) exception('上传失败，找不到上传的文件!');
            if(empty($data['uptype'])) exception('上传失败，找不到上传的文件!');
            $redis_key = $this->imgkey.date('Ymd').'_'.$id;
            $imgJson = [];
            $field = 0;
            $imgInfo = $this->saveImg($id);//保存上传图片
            if($imgInfo == false) exception($this->error?:'保存图片失败');
            $redis = getRedis();
            if(!empty($data['key'])){
                $field = $data['key'];
                $ret = $redis->hGet($redis_key, strval($field));
                if(!empty($ret)) $imgJson = json_decode($ret, true);
                $imgJson[$data['uptype']] = $imgInfo['img'].'***'.$imgInfo['mid'];
                $imgJson = json_encode($imgJson);
                $redis->hSet($redis_key, strval($field), $imgJson);
            }else{
                $len = $redis->hLen($redis_key);
                if($len > 0){
                    $field = $len;
                    $ret = $redis->hGet($redis_key, strval($field));
                    if(!empty($ret)) $imgJson = json_decode($ret, true);
                    if(!empty($imgJson[$data['uptype']])){
                        $field = $len+1;
                        $imgJson = [];
                        $imgJson[$data['uptype']] = $imgInfo['img'].'***'.$imgInfo['mid'];
                        $imgJson = json_encode($imgJson);
                        $redis->hSet($redis_key, strval($field), $imgJson);
                    }elseif(empty($imgJson[$data['uptype']])){
                        $imgJson[$data['uptype']] = $imgInfo['img'].'***'.$imgInfo['mid'];
                        $imgJson = json_encode($imgJson);
                        $redis->hSet($redis_key, strval($len), $imgJson);
                    }else exception('上传失败：文件匹配不成功，请联系客服!');
                }else{
                    $field = 1;
                    $imgJson[$data['uptype']] = $imgInfo['img'].'***'.$imgInfo['mid'];
                    $imgJson = json_encode($imgJson);
                    $redis->hSetNx($redis_key, strval($field), $imgJson);
                }
            }
            $ret = $redis->ttl($redis_key);
            if ($ret === -1) $redis->expire($redis_key, 3600*24*3);
            $imgInfo['key'] = $field;
            $imgInfo['img'] = getApiDominUrl($imgInfo['img']);
            return $imgInfo;
        }catch (\Exception $e){
            $this->error = $e->getMessage();
            return false;
        }
    }

    /*
     * 获取用户上传直播间图片素材mid
     * $id 用户id
     * $key 对应hash表字段
     * $day 储存日期
     */
    public function getUploadImgMidByKey($id,$key,$day=false)
    {
        try{
            $day = !empty($day)?$day:date('Ymd');
            $redis_key = $this->imgkey.$day.'_'.$id;
            $imgJson = [];
            $redis = getRedis();
            $ret = $redis->hGet($redis_key, strval($key));
            if(!empty($ret)) $imgJson = json_decode($ret, true);
            return $imgJson;
        }catch (\Exception $e){
            $this->error = $e->getMessage();
            return false;
        }
    }

    /*
     * 保存图片&提交到微信素材库
     */
    public function saveImg($id)
    {
        try{
            $data = Input('post.');
            if(!empty($_FILES['img'])){
                $m = date('Ym'); //按月份分目录
                $path = $this->path .$m;
                $dir = app()->getRootPath() .'public/uploads/' . $this->path . $m .'/';
                if(!is_dir($dir))  @mkdir($dir,0777); //目录不存在则创建
                $imgInfo = imgUpdate('img',$path,date('YmdHis').'_'.$id);
                if(!isset($imgInfo['result'])) exception($imgInfo['msg']);
                $api = new WxApi();
                $mid = $api->uploadImg(['img'=>app()->getRootPath(). 'public'. $imgInfo['result'],'type'=>$data['type'],'uid'=>$id]);
                if($mid == false) exception($api->error);
                #TODO 推送队列将图片储存到cos
                return ['img'=> $imgInfo['result'], 'mid'=> $mid];
            }
            exception('上传失败，找不到上传的文件!');
            return false;
        }catch (\Exception $e){
            $this->error = $e->getMessage();
            return false;
        }
    }

}
